package nl.nhl.idp;

import java.io.IOException;

import nl.nhl.idp.Components.Network.*;
import nl.nhl.idp.Views.Charts.DataPoint;
import nl.nhl.idp.Views.Charts.DataSet;
import nl.nhl.idp.Views.Charts.SensorChart;
import nl.nhl.idp.Views.StatusView.StatusListView;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ViewFlipper;

/**
 * Main GuestApplication Activity the application itself
 * @author Alex Wijnbeek
 *
 */
public class MainActivity extends Activity
{
	//### CONSTANTS ###
		private final String DEFAULT_IP = "141.252.29.43";
		private final int DEFAULT_PORT = 1338;
		private final int DEFAULT_NAVCOLOR = 0xFFDDDDDD;
		private final int SELECTED_NAVCOLOR = 0xFFFF0000;
	//### END CONSTANTS ###	
	
	//### VARIABLES ###
		//start time
		int currentSec = 0;
		
		//Network
		private NetworkController networkController;
		private ProgressDialog conDialog;
		private AlertDialog alertDialog;
		private EditText ipEditText;
		private EditText portEditText;
		private SensorData currentSensorData;
		
		//ViewFlipper
		private ViewFlipper mainFlipper;
		private ViewFlipper viewFlipper;
		private Animation flipInDownAnim;
		private Animation flipOutDownAnim;
		private Animation flipInUpAnim;
		private Animation flipOutUpAnim;
		
		//statusView
		private StatusListView statusView;
		
		//Charts
		private SensorChart sensorChart_Angle;
		private SensorChart sensorChart_Battery;
		private SensorChart sensorChart_Engine;
		private SensorChart sensorChart_Maze;
		private DataSet data_Angle;
		private DataSet data_Battery;
		private DataSet data_Engine_Voltage;
		private DataSet data_Engine_Current;
		private DataSet data_MazeForward;
		private DataSet data_MazeLeft;
		private DataSet data_MazeRight;
	//### END VARIABLES ###
	
	/** Called when the activity is first created. */
		// TODO finish guest app connection window stuff
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
		
		//### NETWORK ###
		networkController = new NetworkController();
		networkController.SetNetListener(netListener);
		
		ipEditText = (EditText)findViewById(R.id.ipEditText);
		ipEditText.setText(DEFAULT_IP);
		
		portEditText = (EditText)findViewById(R.id.portEditText);
		portEditText.setText(DEFAULT_PORT+"");
		
		// alert dialog stuff
		alertDialog = new AlertDialog.Builder(this).create();
		
		alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
		   public void onClick(DialogInterface dialog, int which) {
		      alertDialog.dismiss();
		   }
		});
		//### END NETWORK ###
		
		//### VIEWFLIPPER ###
		viewFlipper = (ViewFlipper)findViewById(R.id.viewFlipper1);
		mainFlipper = (ViewFlipper)findViewById(R.id.viewFlipper2);
		
		flipInDownAnim = AnimationUtils.loadAnimation(this, R.anim.flipindown);
		flipOutDownAnim = AnimationUtils.loadAnimation(this, R.anim.flipoutdown);
		flipInUpAnim = AnimationUtils.loadAnimation(this, R.anim.flipinup);
		flipOutUpAnim = AnimationUtils.loadAnimation(this, R.anim.flipoutup);
		//### END VIEWFLIPPER ###
		
		//### NAVBAR BUTTONS ###
		((Button)findViewById(R.id.button_Connect)).setOnClickListener(new ButtonClickListener());
		((Button)findViewById(R.id.buttonNav_Data)).setOnClickListener(new ButtonClickListener());
		((Button)findViewById(R.id.buttonNav_Chart01)).setOnClickListener(new ButtonClickListener());
		((Button)findViewById(R.id.buttonNav_Chart02)).setOnClickListener(new ButtonClickListener());
		((Button)findViewById(R.id.buttonNav_Chart03)).setOnClickListener(new ButtonClickListener());
		((Button)findViewById(R.id.buttonNav_Chart04)).setOnClickListener(new ButtonClickListener());
		
		ResetButtonsColor();
		SetActiveButton(((Button)findViewById(R.id.buttonNav_Data)));
		//### END NAVBAR BUTTONS ###
		
		
		statusView = (StatusListView)findViewById(R.id.dataListView);
		
		//### CHARTS ###
		sensorChart_Angle = (SensorChart)findViewById(R.id.sensorChart01);
		sensorChart_Battery = (SensorChart)findViewById(R.id.sensorChart02);
		sensorChart_Engine = (SensorChart)findViewById(R.id.sensorChart03);
		sensorChart_Maze = (SensorChart)findViewById(R.id.sensorChart04);
		
		data_Angle = new DataSet("Hellingshoek");
		data_Angle.SetColor(Color.GREEN);
        
		data_Battery = new DataSet("Accuspanning");
		data_Battery.SetColor(Color.RED);
		
		data_Engine_Voltage = new DataSet("Motorspanning");
		data_Engine_Voltage.SetColor(Color.CYAN);
		data_Engine_Current = new DataSet("Motorstroom");
		data_Engine_Current.SetColor(Color.RED);
		

		data_MazeForward = new DataSet("Maze Forward");
		data_MazeForward.SetColor(Color.CYAN);
		data_MazeLeft = new DataSet("Maze Left");
		data_MazeLeft.SetColor(Color.GREEN);
		data_MazeRight = new DataSet("Maze Right");
		data_MazeRight.SetColor(Color.RED);
		
		sensorChart_Angle.SetData("Hellingshoek", data_Angle);
		sensorChart_Battery.SetData("Accuspanning", data_Battery);
		sensorChart_Engine.SetData("Motorspanning", data_Engine_Voltage);
		sensorChart_Engine.SetData("Motorstroom", data_Engine_Current);
		sensorChart_Maze.SetData("Maze Forward", data_MazeForward);
		sensorChart_Maze.SetData("Maze Left", data_MazeLeft);
		sensorChart_Maze.SetData("Maze Right", data_MazeRight);
		//### END CHARTS ###
		
		currentSensorData = new SensorData();
	}
	
	//### NAVBAR ###
	/**
	 * Sets the specified button to it's active color
	 * @param button
	 */
	private void SetActiveButton(Button button)
	{
		button.getBackground().setColorFilter(SELECTED_NAVCOLOR, Mode.MULTIPLY);
	}
	
	/**
	 * Resets the color of all nav buttons to their default color
	 */
	private void ResetButtonsColor()
	{
		((Button)findViewById(R.id.buttonNav_Data)).getBackground().setColorFilter(DEFAULT_NAVCOLOR, Mode.MULTIPLY);
		((Button)findViewById(R.id.buttonNav_Chart01)).getBackground().setColorFilter(DEFAULT_NAVCOLOR, Mode.MULTIPLY);
		((Button)findViewById(R.id.buttonNav_Chart02)).getBackground().setColorFilter(DEFAULT_NAVCOLOR, Mode.MULTIPLY);
		((Button)findViewById(R.id.buttonNav_Chart03)).getBackground().setColorFilter(DEFAULT_NAVCOLOR, Mode.MULTIPLY);
		((Button)findViewById(R.id.buttonNav_Chart04)).getBackground().setColorFilter(DEFAULT_NAVCOLOR, Mode.MULTIPLY);
	}
	
	/**
	 * Flips the viewFlipper(holding charts) to the given index, and sets the right animations
	 * @param viewIndex
	 */
	private void FlipView(int viewIndex)
	{
		if(viewFlipper.getDisplayedChild() > viewIndex)
		{
			viewFlipper.setInAnimation(flipInUpAnim);
			viewFlipper.setOutAnimation(flipOutUpAnim);
			viewFlipper.setDisplayedChild(viewIndex);
		}
		else if(viewFlipper.getDisplayedChild() < viewIndex)
		{
			viewFlipper.setInAnimation(flipInDownAnim);
			viewFlipper.setOutAnimation(flipOutDownAnim);
			viewFlipper.setDisplayedChild(viewIndex);
		}
	}
	//### END NAVBAR ###
	
	//### LISTENERS ###
	/**
	 * Listens for buttonclick events
	 * @author Alex Wijnbeek
	 */
	public class ButtonClickListener implements OnClickListener
	{
		public void onClick(View view)
		{	
			ResetButtonsColor();
			
			switch(view.getId())
			{
				case R.id.button_Connect:
				{
					//connect to vehicle here...
					String ip = ipEditText.getText().toString();
					int port = Integer.parseInt(portEditText.getText().toString());
					
					networkController.SetIpAddress(ip);
					networkController.SetPort(port);
					
					// show trying to connect dialog
					conDialog = ProgressDialog.show(view.getContext(), "",
							"Trying to connect to "
							+ ip+":"+port, false);
					
					//try to connect
					networkController.Connect();

					//hide the keyboard!
					InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
				    imm.hideSoftInputFromWindow(mainFlipper.getApplicationWindowToken(), 0);
				    
				}break;
				
				case R.id.buttonNav_Data:
					FlipView(0);
					SetActiveButton(((Button)view));
					break;
				case R.id.buttonNav_Chart01:
					FlipView(1);
					SetActiveButton(((Button)view));
					break;
				case R.id.buttonNav_Chart02:
					FlipView(2);
					SetActiveButton(((Button)view));
					break;
				case R.id.buttonNav_Chart03:
					FlipView(3);
					SetActiveButton(((Button)view));
					break;
				case R.id.buttonNav_Chart04:
					FlipView(4);
					SetActiveButton(((Button)view));
					break;
			}
		}
	}
	
	/**
	 * Handle network events
	 */
	protected NetListener netListener = new NetListener()
	{
		public void onNetEvent(NetEvent event)
		{
			statusView.SetItem("LastMsg", event.getMsg());
			
			switch (event.getEventID())
			{
				case TYPE_CON:
				{
					if (conDialog != null)
						conDialog.dismiss();

					// show connected status
					statusView.SetItem("NetStatus", "Connected");
					
					//clear chart data
					data_Angle.Clear();
					data_Battery.Clear();
					data_Engine_Voltage.Clear();
					data_MazeForward.Clear();
					data_MazeLeft.Clear();
					data_MazeRight.Clear();
					
					//reset chart pan/zoom values
					sensorChart_Angle.Reset();
					sensorChart_Battery.Reset();
					sensorChart_Engine.Reset();
					sensorChart_Maze.Reset();
					
					currentSec = 0;
					
					// if we are connected we want to show the dashboard
					mainFlipper.setDisplayedChild(1);
				}
					break;
				case TYPE_DISCON:
				{
					// try to disconnect properly
					try
					{
						networkController.Disconnect();
					} catch (IOException e)
					{
						e.printStackTrace();
					}
					
					alertDialog.setMessage("Disconnected!");
					alertDialog.show();

					// show connected status
					statusView.SetItem("NetStatus", "Disconnected");
				}
					break;
				case TYPE_RECEIVE:
				{
					statusView.SetItem("MessageStatus", "DataReceived");
					
                    if( (event.getMsgID() & 0xFF) == ProtocolOpcodes.V_SENSOR.Opcode() )
                    {
                        byte[] data = event.getData();
                        
                        // fill data in the structure
                        currentSensorData.setAccuspanning( data[0] & 0xFF );
                        currentSensorData.setMotorspanning( data[1] & 0xFF );
                        currentSensorData.setMotorstroom( data[2] & 0xFF );
                        currentSensorData.setHellingshoek( (data[3] & 0xFF) - 60 );
                        currentSensorData.setMazeSensors( (short) (data[4] & 0xFF), (short) (data[5] & 0xFF), (short) (data[6] & 0xFF));
                        
                        //put data in statusview
                        statusView.SetItem("Angle", currentSensorData.getHellingshoek(), "degrees");
                        statusView.SetItem("Battery", currentSensorData.getAccuspanning(),"volt");
                        statusView.SetItem("Engine Voltage", currentSensorData.getMotorspanning(), "volt");
                        statusView.SetItem("Engine Current", currentSensorData.getMotorstroom(), "mA");
                        statusView.SetItem("Maze Forward", currentSensorData.getMazeSensorForward(), "cm");
                        statusView.SetItem("Maze Left", currentSensorData.getMazeSensorLeft(), "cm");
                        statusView.SetItem("Maze Right", currentSensorData.getMazeSensorRight(), "cm");
                        
                        // put data in charts
                        data_Angle.Add(new DataPoint(currentSec, currentSensorData.getHellingshoek()));
                        data_Battery.Add(new DataPoint(currentSec, currentSensorData.getAccuspanning()));
                        data_Engine_Voltage.Add(new DataPoint(currentSec, currentSensorData.getMotorspanning()));
                        data_MazeForward.Add(new DataPoint(currentSec, currentSensorData.getMazeSensorForward()));
                        data_MazeLeft.Add(new DataPoint(currentSec, currentSensorData.getMazeSensorLeft()));
                        data_MazeRight.Add(new DataPoint(currentSec, currentSensorData.getMazeSensorRight()));
                		
                        //increment timescale
                		currentSec++;
                		
                		//invalidate charts
                		sensorChart_Angle.invalidate();
            			sensorChart_Battery.invalidate();
            			sensorChart_Engine.invalidate();
            			sensorChart_Maze.invalidate();
                    }
					
				}
					break;
				case TYPE_NOTIFI:
				{
					if (conDialog != null)
						conDialog.dismiss();
					
					alertDialog.setMessage(event.getMsg());
					alertDialog.show();
					
					// show connected status
					statusView.SetItem("NetStatus", "Disconnected");
				}
					break;
			}
		}
	};
	//### END LISTENERS ###
	
	/**
	 * Key down event handler
	 */
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event)
	{
		if (keyCode == KeyEvent.KEYCODE_BACK)
		{
			if(mainFlipper.getDisplayedChild() != 0)
			{
				try
				{
					if(networkController.IsConnected())
						networkController.Disconnect();
				} catch (IOException e)
				{
					e.printStackTrace();
				}
				
				// show connected status
				statusView.SetItem("NetStatus", "Disconnected");
				
				mainFlipper.setDisplayedChild(0);
			}
			else
			{
				System.runFinalizersOnExit(true);
				System.exit(0);
			}
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}
}